#include "ast.hpp"
#include "lexer.hpp"
#include "visitor.hpp"

#include <algorithm>
using namespace std;

/* constructors. */
ListNode::ListNode() {
    _node_list = new vector<Node*>();
}

void ListNode::add(Node* n) {
    _node_list->push_back(n);
    n->set_parent(this);
}

void ListNode::remove(Node* n) {
    auto it = find(_node_list->begin(), _node_list->end(), n);

    if (it != _node_list->end()) {
        _node_list->erase(it);
    }
}

void ListNode::insert(Node* n, Node* t) {
    auto it = find(_node_list->begin(), _node_list->end(), n);

    if (it != _node_list->end()) {
        _node_list->insert(it, t);
    }
    else {
        _node_list->push_back(t);
    }
}

VarNode::VarNode(Token* t) {
    _name = string(t->_value, t->_length);
}

FuncDefNode::FuncDefNode(Token* t) {
    _name = string(t->_value, t->_length);
}

void BinaryOp::set_left(Node* left) {
    _left = left;
    _left->set_parent(this);
}

void BinaryOp::set_right(Node* right) {
    _right = right;
    _right->set_parent(this);
}

/**
 * visitor pattern for AST.
 */
void AssignNode::accept(Visitor* v) {
    v->visit(this);
}

void VarNode::accept(Visitor* v) {
    v->visit(this);
}

void CmpNode::accept(Visitor* v) {
    v->visit(this);
}

void ConstInt::accept(Visitor* v) {
    v->visit(this);
}

void ConstArray::accept(Visitor* v) {
    v->visit(this);
}

ConstString::ConstString(int length, const char* s) {
    _value = new char[length + 1];
    strncpy(_value, s, length);
    _value[length] = '\0';
    _length = length;
}

ConstString::~ConstString() {
    delete[] _value;
    _value = nullptr;
}

void ConstString::accept(Visitor* v) {
    v->visit(this);
}

void PrintNode::accept(Visitor* v) {
    v->visit(this);
}

void ReturnNode::accept(Visitor* v) {
    v->visit(this);
}

void IfNode::accept(Visitor* v) {
    v->visit(this);
}

void WhileNode::accept(Visitor* v) {
    v->visit(this);
}

void ParamDefNode::accept(Visitor* v) {
    v->visit(this);
}

void VarDefNode::accept(Visitor* v) {
    v->visit(this);
}

void ListNode::accept(Visitor* v) {
    v->visit(this);
}

void BinaryOp::accept(Visitor* v) {
    v->visit(this);
}

void LogicNotNode::accept(Visitor* v) {
    v->visit(this);
}

void FuncDefNode::accept(Visitor* v) {
    v->visit(this);
}

void CallNode::accept(Visitor* v) {
    v->visit(this);
}

void SubscrNode::accept(Visitor* v) {
    v->visit(this);
}

void LambdaDef::accept(Visitor* visitor) {
    visitor->visit(this);
}

void TypeFuncDefNode::accept(Visitor* visitor) {
    visitor->visit(this);
}

void TypeVarDefNode::accept(Visitor* visitor) {
    visitor->visit(this);
}

void ArrayTypeNode::accept(Visitor* visitor) {
    visitor->visit(this);
}

void ArrowTypeNode::accept(Visitor* v) {
    v->visit(this);
}

void TypeConstInt::accept(Visitor* v) {
    v->visit(this);
}

void TypeCallNode::accept(Visitor* v) {
    v->visit(this);
}

void TypeVarNode::accept(Visitor* v) {
    v->visit(this);
}

void BuiltinConst::accept(Visitor* visitor) {
    visitor->visit(this);
}

/*
 * some initialization.
 */

BuiltinConst* BuiltinConst::UnitNode = new BuiltinConst(BuiltinConst::UNIT);
BuiltinConst* BuiltinConst::TrueNode = new BuiltinConst(BuiltinConst::TRUE);
BuiltinConst* BuiltinConst::FalseNode = new BuiltinConst(BuiltinConst::FALSE);

